#include "Convert_Device.h"
#include "JNIHelper.h"
#include "Device.h"

ST_Device *Convert_Device::java2Object(jobject obj) {
  auto pEnv = JNIHelper::Instance()->getEnv();
  jclass deviceClass = pEnv->FindClass("com/fan/play/media/engine/CaptureDevice");
  auto devIDField = pEnv->GetFieldID(deviceClass, "devID", "I");
  auto devTypeField = pEnv->GetFieldID(deviceClass, "devType", "I");
  auto devStateField = pEnv->GetFieldID(deviceClass, "devState", "I");

  int32_t devID = pEnv->GetIntField(obj, devIDField);
  int32_t devType = pEnv->GetIntField(obj, devTypeField);
  int32_t devState = pEnv->GetIntField(obj, devStateField);

  IDevice *pDevice = nullptr;
  if (devType == DeviceType_Camera) {
    jclass cameraDevice = pEnv->FindClass("com/fan/play/media/engine/CaptureDeviceCamera");
    auto widthField = pEnv->GetFieldID(cameraDevice, "width", "I");
    auto heightField = pEnv->GetFieldID(cameraDevice, "height", "I");
    auto frameRateField = pEnv->GetFieldID(cameraDevice, "frameRate", "I");
    int32_t width = pEnv->GetIntField(obj, widthField);
    int32_t height = pEnv->GetIntField(obj, heightField);
    int32_t frameRate = pEnv->GetIntField(obj, frameRateField);

    pDevice = new CameraDevice();
    auto pCameraDevice = dynamic_cast<CameraDevice *>(pDevice);
    pCameraDevice->width = width;
    pCameraDevice->height = height;
    pCameraDevice->frameRate = frameRate;
    return pDevice;
  } else if (devType == DeviceType_Audio) {
    jclass audioDevice = pEnv->FindClass("com/fan/play/media/engine/CaptureDeviceAudio");
    auto sampleRateField = pEnv->GetFieldID(audioDevice, "sampleRate", "I");
    auto channelNumField = pEnv->GetFieldID(audioDevice, "channelNum", "I");
    auto samplesBitPerField = pEnv->GetFieldID(audioDevice, "samplesBitPer", "I");
    int32_t sampleRate = pEnv->GetIntField(obj, sampleRateField);
    int32_t channelNum = pEnv->GetIntField(obj, channelNumField);
    int32_t samplesBitPer = pEnv->GetIntField(obj, samplesBitPerField);

    pDevice = new AudioDevice();
    auto pAudioDevice = dynamic_cast<AudioDevice *>(pDevice);
    pAudioDevice->sampleRate = sampleRate;
    pAudioDevice->channelNum = channelNum;
    pAudioDevice->samplesBitPer = samplesBitPer;
  } else {
    jclass ipcameraDevice = pEnv->FindClass("com/fan/play/media/engine/CaptureDeviceIPCamera");
    auto stStreamField = pEnv->GetFieldID(ipcameraDevice, "stStream", "Ljava/lang/String;");
    auto isSoftDecodeField = pEnv->GetFieldID(ipcameraDevice, "isSoftDecode", "Z");
    auto jstStream = (jstring) pEnv->GetObjectField(obj, stStreamField);
    bool isSoftDecode = pEnv->GetBooleanField(obj, isSoftDecodeField);
    auto stStream = pEnv->GetStringUTFChars(jstStream, JNI_FALSE);

    pDevice = new IPCameraDevice();
    auto pIPCameraDevice = dynamic_cast<IPCameraDevice *>(pDevice);
    strcpy(pIPCameraDevice->stStream, stStream);
    pIPCameraDevice->isSoftDecode = isSoftDecode;
    pEnv->ReleaseStringUTFChars(jstStream, stStream);
  }

  pDevice->devID = devID;
  pDevice->devType = static_cast<DeviceType>(devType);
  pDevice->devState = static_cast<DeviceState>(devState);
  return pDevice;
}

jobject Convert_Device::object2Java(ST_Device *obj) {
  auto pEnv = JNIHelper::Instance()->getEnv();
  jclass deviceClass = pEnv->FindClass("com/fan/play/media/engine/CaptureDevice");
  auto devIDField = pEnv->GetFieldID(deviceClass, "devID", "I");
  auto devTypeField = pEnv->GetFieldID(deviceClass, "devType", "I");
  auto devStateField = pEnv->GetFieldID(deviceClass, "devState", "I");

  jobject pDevice = nullptr;
  if (obj->devType == DeviceType_Camera) {
    auto pCameraDevice = dynamic_cast<CameraDevice *>(obj);
    jclass cameraDevice = pEnv->FindClass("com/fan/play/media/engine/CaptureDeviceCamera");
    auto widthField = pEnv->GetFieldID(cameraDevice, "width", "I");
    auto heightField = pEnv->GetFieldID(cameraDevice, "height", "I");
    auto frameRateField = pEnv->GetFieldID(cameraDevice, "frameRate", "I");

    jmethodID initID = pEnv->GetMethodID(cameraDevice, "<init>", "()V");
    pDevice = pEnv->NewObject(cameraDevice, initID);

    pEnv->SetIntField(pDevice, widthField, pCameraDevice->width);
    pEnv->SetIntField(pDevice, heightField, pCameraDevice->height);
    pEnv->SetIntField(pDevice, frameRateField, pCameraDevice->frameRate);
  } else if (obj->devType == DeviceType_Audio) {
    auto pAudioDevice = dynamic_cast<AudioDevice *>(obj);
    jclass audioDevice = pEnv->FindClass("com/fan/play/media/engine/CaptureDeviceAudio");
    auto sampleRateField = pEnv->GetFieldID(audioDevice, "sampleRate", "I");
    auto channelNumField = pEnv->GetFieldID(audioDevice, "channelNum", "I");
    auto samplesBitPerField = pEnv->GetFieldID(audioDevice, "samplesBitPer", "I");

    jmethodID initID = pEnv->GetMethodID(audioDevice, "<init>", "()V");
    pDevice = pEnv->NewObject(audioDevice, initID);

    pEnv->SetIntField(pDevice, sampleRateField, pAudioDevice->sampleRate);
    pEnv->SetIntField(pDevice, channelNumField, pAudioDevice->channelNum);
    pEnv->SetIntField(pDevice, samplesBitPerField, pAudioDevice->samplesBitPer);
  } else {
    auto pIPCameraDevice = dynamic_cast<IPCameraDevice *>(obj);
    jclass ipcameraDevice = pEnv->FindClass("com/fan/play/media/engine/CaptureDeviceIPCamera");
    auto stStreamField = pEnv->GetFieldID(ipcameraDevice, "stStream", "Ljava/lang/String;");
    auto isSoftDecodeField = pEnv->GetFieldID(ipcameraDevice, "isSoftDecode", "Z");

    jmethodID initID = pEnv->GetMethodID(ipcameraDevice, "<init>", "()V");
    pDevice = pEnv->NewObject(ipcameraDevice, initID);

    jstring jstStream = pEnv->NewStringUTF(pIPCameraDevice->stStream);
    pEnv->SetObjectField(pDevice, stStreamField, jstStream);
    pEnv->SetBooleanField(pDevice, isSoftDecodeField, pIPCameraDevice->isSoftDecode);
  }

  pEnv->SetIntField(pDevice, devIDField, obj->devID);
  pEnv->SetIntField(pDevice, devTypeField, (jint) obj->devType);
  pEnv->SetIntField(pDevice, devStateField, (jint) obj->devState);
  return pDevice;
}

jobject Convert_Device::objectList2JavaList(std::list<IDevice *> &deviceList) {
  auto pEnv = JNIHelper::Instance()->getEnv();
  jclass deviceClass = pEnv->FindClass("java/util/ArrayList");
  jmethodID initID = pEnv->GetMethodID(deviceClass, "<init>", "()V");
  jmethodID addID = pEnv->GetMethodID(deviceClass, "add", "(Ljava/lang/Object;)Z");
  jobject javaDeviceList = pEnv->NewObject(deviceClass, initID);
  std::for_each(deviceList.begin(), deviceList.end(),
                [&](IDevice *pItem) {
                  jobject javaDevice = object2Java(pItem);
                  pEnv->CallBooleanMethod(javaDeviceList, addID, javaDevice);
                });

  return javaDeviceList;
}
